package org.internna.expensetracker.model;

import java.util.Date;
import java.util.List;
import javax.persistence.OneToOne;
import javax.persistence.Temporal;
import javax.persistence.ManyToOne;
import javax.persistence.FetchType;
import javax.persistence.NamedQuery;
import javax.persistence.NamedQueries;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import org.internna.expensetracker.model.Investment;
import org.springframework.roo.addon.entity.RooEntity;
import org.springframework.roo.addon.tostring.RooToString;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.roo.addon.serializable.RooSerializable;

@RooEntity
@RooJavaBean
@RooSerializable
@RooToString(excludeFields = {"investment", "transaction"})
@NamedQueries({
	@NamedQuery(name = InvestmentPrice.FIND_PRICES, query = "SELECT i FROM InvestmentPrice i WHERE investment = :investment ORDER BY updateTime DESC"),
	@NamedQuery(name = InvestmentPrice.FIND_LAST_PRICE, query = "SELECT i FROM InvestmentPrice i WHERE (investment = :investment) AND (updateTime < :updateTime) ORDER BY updateTime DESC")
})
public class InvestmentPrice implements Comparable<InvestmentPrice> {

    private static final long serialVersionUID = 2731402583426861599L;

    protected static final String FIND_PRICES = "findInvestmentPrices";
    protected static final String FIND_LAST_PRICE = "findLastInvestmentPrice";

    @NotNull
    private Double price = new Double(1.0);

    @NotNull
    @DateTimeFormat(style = "S-")
    @Temporal(TemporalType.TIMESTAMP)
    private Date updateTime;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    private Investment investment;

    @OneToOne(fetch = FetchType.LAZY, mappedBy = "price")
    private InvestmentTransaction transaction;

    public static InvestmentPrice findLastInvestmentPrice(Investment investment) {
    	return findInvestmentPrice(investment, new Date());
    }

    public static InvestmentPrice findInvestmentPrice(Investment investment, Date updateTime) {
    	try {
    		return entityManager().createNamedQuery(FIND_LAST_PRICE, InvestmentPrice.class)
    				.setParameter("investment", investment)
    				.setParameter("updateTime", updateTime)
    				.setMaxResults(1).getSingleResult();
    	} catch (RuntimeException ex) {
    		return null;
    	}
    }

    public static List<InvestmentPrice> findInvestmentPricesByInvestment(Investment investment) {
    	return entityManager().createNamedQuery(FIND_PRICES, InvestmentPrice.class)
				.setParameter("investment", investment)
				.getResultList();
    }

    public final boolean belongsTo(Investment investment) {
        return investment != null && getInvestment() != null && investment.equals(getInvestment());
    }

    @Override public int compareTo(InvestmentPrice other) {
        return other == null ? -1 : other.updateTime == null ? -1 : updateTime == null ? 1 : updateTime.compareTo(other.updateTime);
    }

    @Override public int hashCode() {
        return 123 + super.hashCode() + (price != null ? price.hashCode() : 963) + (updateTime != null ? updateTime.hashCode() : 562);
    }

}
